use core::ffi::c_void;

use crate::{protocol::device_path::EfiDevicePathProtocol, EfiStatus};

use super::{event::EfiEvent, EfiGuid, EfiHandle, EfiInterfaceType};

pub type EfiInstallProtocolInterface = extern "efiapi" fn(
    handle: *mut EfiHandle,
    protocol: *const EfiGuid,
    interfaceType: EfiInterfaceType,
    interface: *const c_void,
) -> EfiStatus;

pub type EfiUinstallProtocolInterface = extern "efiapi" fn(
    handle: EfiHandle,
    protocol: *const EfiGuid,
    inteface: *const c_void,
) -> EfiStatus;

pub type ReinstallProtocolInterface = extern "efiapi" fn(
    handle: EfiHandle,
    protocol: *const EfiGuid,
    old_interface: *const c_void,
    new_interface: *const c_void,
) -> EfiStatus;
pub type RegisterProtocolNotify = extern "efiapi" fn(
    protocol: *const EfiGuid,
    event: EfiEvent,
    registration: *mut *const c_void,
) -> EfiStatus;
pub type LocateHandle = extern "efiapi" fn(
    search_type: EfiLocateSearchType,
    protocol: *const EfiGuid,
    search_key: c_void,
    buffer_size: *mut usize,
    buffer: *mut EfiHandle,
) -> EfiStatus;
pub type HandleProtocol = extern "efiapi" fn(
    handle: EfiHandle,
    protocol: *const EfiGuid,
    interface: *mut *const c_void,
) -> EfiStatus;
pub type LocateDevicePath = extern "efiapi" fn(
    protocol: *const EfiGuid,
    device_path: *mut *const EfiDevicePathProtocol,
    device: *mut EfiHandle,
) -> EfiStatus;
pub type OpenProtocol = extern "efiapi" fn(
    handle: EfiHandle,
    protocol: *const EfiGuid,
    interface: *mut *const c_void,
    agent_handle: EfiHandle,
    controller_handle: EfiHandle,
    attributes: u32,
) -> EfiStatus;
pub type CloseProtocol = extern "efiapi" fn(
    handle: EfiHandle,
    protocol: *const EfiGuid,
    agent_handle: EfiHandle,
    controller_handle: EfiHandle,
) -> EfiStatus;
pub type OpenProtocolInformation = extern "efiapi" fn(
    handle: EfiHandle,
    protocol: *const EfiGuid,
    entry_buffer: *mut *const EfiOpenProtocolInformationEntry,
    entry_count: *mut usize,
) -> EfiStatus;
pub type ConnectController = extern "efiapi" fn(
    controller_handle: EfiHandle,
    driver_image_handle: *const EfiHandle,
    remaining_device_path: *const EfiDevicePathProtocol,
    recursive: bool,
) -> EfiStatus;
pub type DisconnectController = extern "efiapi" fn(
    controller_handle: EfiHandle,
    driver_image_handle: EfiHandle,
    child_handle: EfiHandle,
) -> EfiStatus;
pub type ProtocolsPerHandle = extern "efiapi" fn(
    handle: EfiHandle,
    protocol_buffer: *mut *const *const EfiGuid,
    protocol_buffer_count: *mut usize,
) -> EfiStatus;
pub type LocateHandleBuffer = extern "efiapi" fn(
    search_type: EfiLocateSearchType,
    protocol: *const EfiGuid,
    search_key: *const c_void,
    no_handles: *mut usize,
    buffer: *mut *const EfiHandle,
) -> EfiStatus;
pub type LocateProtocol = extern "efiapi" fn(
    protocol: *const EfiGuid,
    registration: *const c_void,
    interface: *mut *const c_void,
) -> EfiStatus;
pub type InstallMultipleProtocolInterfaces =
    extern "C" fn(handle: *mut EfiHandle, ...) -> EfiStatus;
pub type UninstallMultipleProtocolInterfaces = extern "C" fn(handle: EfiHandle, ...) -> EfiStatus;

#[repr(C)]
pub enum EfiLocateSearchType {
    AllHandles,
    ByRegisterNotify,
    ByProtocol,
}
#[repr(C)]
pub struct EfiOpenProtocolInformationEntry {
    pub agent_handle: EfiHandle,
    pub controller_handle: EfiHandle,
    pub attributes: u32,
    pub open_count: u32,
}
pub const EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL: u32 = 0x00000001;
pub const EFI_OPEN_PROTOCOL_GET_PROTOCOL: u32 = 0x00000002;
pub const EFI_OPEN_PROTOCOL_TEST_PROTOCOL: u32 = 0x00000004;
pub const EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER: u32 = 0x00000008;
pub const EFI_OPEN_PROTOCOL_BY_DRIVER: u32 = 0x00000010;
pub const EFI_OPEN_PROTOCOL_EXCLUSIVE: u32 = 0x00000020;
